import { Observable, EMPTY } from 'rxjs';
import { warn, Collider, isValid, ITriggerEvent, ICollisionEvent } from "cc";

/**
 * IMPORTANT:
 * 在3.7.1中首次使用，然而放在常规的useObs即onLoad中进行绑定，将不起作用，
 * 请放在start中进行绑定，可使用滞后绑定策略：
 * 
    start() {
        this.getMainSubscription().add(BindColliderCollision(this._collider).subscribe(_ => {
            if (_.event.type == 'onCollisionEnter') {
                if (_.event.otherCollider.node.name == 'enemy') {
                    this.log('hit enemy!');
                }
            }
        }));
    }
 */

export function BindColliderTrigger(collider: Collider): Observable<{ event: ITriggerEvent, collider: Collider }> {
    if (!collider) { warn('BindColliderTrigger, collider is null'); return EMPTY; }
    return new Observable(observer => {
        const onTriggerEnterCallback = event => {
            observer.next({ event, collider });
        };
        const onTriggerStayCallback = event => {
            observer.next({ event, collider });
        };
        const onTriggerExitCallback = event => {
            observer.next({ event, collider });
        };
        collider.on('onTriggerEnter', onTriggerEnterCallback, this);
        collider.on('onTriggerStay', onTriggerStayCallback, this);
        collider.on('onTriggerExit', onTriggerExitCallback, this);
        return () => {
            if (isValid(collider?.node)) {
                collider.off('onTriggerEnter', onTriggerEnterCallback, this);
                collider.off('onTriggerStay', onTriggerStayCallback, this);
                collider.off('onTriggerExit', onTriggerExitCallback, this);
            }
        }
    })
}

export function BindColliderCollision(collider: Collider): Observable<{ event: ICollisionEvent, collider: Collider }> {
    if (!collider) { warn('BindColliderCollision, collider is null'); return EMPTY; }
    return new Observable(observer => {
        const onCollisionEnterCallback = event => {
            observer.next({ event, collider });
        };
        const onCollisionStayCallback = event => {
            observer.next({ event, collider });
        };
        const onCollisionExitCallback = event => {
            observer.next({ event, collider });
        };
        collider.on('onCollisionEnter', onCollisionEnterCallback, this);
        collider.on('onCollisionStay', onCollisionStayCallback, this);
        collider.on('onCollisionExit', onCollisionExitCallback, this);
        return () => {
            if (isValid(collider?.node)) {
                collider.off('onCollisionEnter', onCollisionEnterCallback, this);
                collider.off('onCollisionStay', onCollisionStayCallback, this);
                collider.off('onCollisionExit', onCollisionExitCallback, this);
            }
        }
    })
}